#include<thread>
#include<condition_variable>
#include<mutex>

#include<unistd.h>

#include<functional>
#include<queue>

void Task(const std::string& s)
{
	cout << s << " is running" << endl;
}

using FUNC = std::function<void(const std::string&)>;

class CPqueue
{
public:
	CPqueue(size_t capacity)
		: _capacity(capacity)
	{}

	bool IsFull()
	{
		return _capacity == _q.size();
	}

	bool IsEmpty()
	{
		return _q.size() == 0;
	}

	void PushTask(FUNC task)
	{
		std::unique_lock<std::mutex> ul(_mtx);
		while(IsFull())
			_full.wait(ul);

		//_full.wait(ul, [this]() {return !IsFull(); });

		_q.push(task);

        //cout << _q.size() << endl;

		_empty.notify_one();
	}

	/*void PopTask(FUNC& task)
	{
		std::unique_lock<std::mutex> ul(_mtx);
		while (IsEmpty())
			_full.wait(ul);

		task = _q.front();
		_q.pop();

		_full.notify_one();
	}
	*/

	bool PopTask(FUNC& task)
	{
		std::unique_lock<std::mutex> ul(_mtx);
		/*while (_q.empty())
			_empty.wait(ul);*/

		_empty.wait(ul, [this]() {return !IsEmpty(); });

		task = std::move(_q.front());
		_q.pop();

		_full.notify_one();
		return true;
	}
private:
	std::condition_variable _full;
	std::condition_variable _empty;
	
	std::mutex _mtx;
	std::queue<FUNC> _q;
	size_t _capacity;
};

